package com.tianji.StragyHttp.utils;

import cn.hutool.core.util.StrUtil;
import com.tianji.exception.BizException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * redis工具类
 * @author Dvnuo
 * @date 2017/4/12
 */
public class RedisKit {

    private static StringRedisTemplate stringRedisTemplate = SpringContextHolder.getBean("stringRedisTemplate");

    private static RedisTemplate<String, Object> redisTemplate = SpringContextHolder.getBean("redisTemplate");


    /**
     * redis的key
     * 形式为：
     * 表名:主键名:主键值
     *
     * @param tableName 表名
     * @param majorKey 主键名
     * @param majorKeyValue 主键值
     * @return
     */
    public static String getKey(String tableName,String majorKey,String majorKeyValue){
        StringBuffer buffer = new StringBuffer();
        buffer.append(tableName).append(":");
        buffer.append(majorKey).append(":");
        buffer.append(majorKeyValue).append(":");
        return buffer.toString();
    }


    /**
     * 删除缓存<br>
     * 根据key精确匹配删除
     * @param key
     */
    public static void del(String... key){
        if(key!=null && key.length > 0){
            if(key.length == 1){
                redisTemplate.delete(key[0]);
            }else{
                redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
            }
        }
    }

    /**
     * 取得缓存（int型）
     * @param key
     * @return
     */
    public static Integer getInt(String key){
        String value = stringRedisTemplate.boundValueOps(key).get();
        if(StrUtil.isNotBlank(value)){
            return Integer.valueOf(value);
        }
        return null;
    }

    /**
     * 取得缓存（字符串类型）
     * @param key
     * @return
     */
    public static String getStr(String key){
        return stringRedisTemplate.boundValueOps(key).get();
    }

    /**
     * 获取缓存<br>
     * 注：基本数据类型(Character除外)，请直接使用get(String key, Class<T> clazz)取值
     * @param key
     * @return
     */
    public static Object getObj(String key){
        return redisTemplate.boundValueOps(key).get();
    }


    /**
     * 获取缓存<br>
     * 注：该方法暂不支持Character数据类型
     * @param key   key
     * @param clazz 类型
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T get(String key, Class<T> clazz) {
        return (T)redisTemplate.boundValueOps(key).get();
    }

    /**
     * 获取Keys
     * @param pattern
     * @return
     */
    public static Set<String> getKeys(String pattern) {
        return redisTemplate.keys(pattern);
    }


    /**
     * 将value对象写入缓存
     * @param key
     * @param value
     * @param time 失效时间(秒)
     */
    public static void set(String key, Object value, long time ,TimeUnit timeUnit){
        if(value instanceof String){
            stringRedisTemplate.opsForValue().set(key, value.toString());
        }else if(value instanceof Integer){
            stringRedisTemplate.opsForValue().set(key, value.toString());
        }else if(value instanceof Double){
            stringRedisTemplate.opsForValue().set(key, value.toString());
        }else if(value instanceof Float){
            stringRedisTemplate.opsForValue().set(key, value.toString());
        }else if(value instanceof Short){
            stringRedisTemplate.opsForValue().set(key, value.toString());
        }else if(value instanceof Long){
            stringRedisTemplate.opsForValue().set(key, value.toString());
        }else if(value instanceof Boolean){
            stringRedisTemplate.opsForValue().set(key, value.toString());
        }else{
            redisTemplate.opsForValue().set(key, value);
        }
        if(time > 0){
            redisTemplate.expire(key, time, timeUnit);
        }
    }

    /**
     * 获取double类型值
     * @param key
     * @return
     */
    public static double getDouble(String key) {
        String value = stringRedisTemplate.boundValueOps(key).get();
        if(StrUtil.isNotBlank(value)){
            return Double.valueOf(value);
        }
        return 0d;
    }

    /**
     * 设置double类型值
     * @param key
     * @param value
     * @param time 失效时间(秒)
     */
    public static void setDouble(String key, double value, long time) {
        stringRedisTemplate.opsForValue().set(key, String.valueOf(value));
        if(time > 0){
            stringRedisTemplate.expire(key, time, TimeUnit.SECONDS);
        }
    }

    /**
     * 设置double类型值
     * @param key
     * @param value
     * @param time 失效时间(秒)
     */
    public static void setInt(String key, int value, long time) {
        stringRedisTemplate.opsForValue().set(key, String.valueOf(value));
        if(time > 0){
            stringRedisTemplate.expire(key, time, TimeUnit.SECONDS);
        }
    }

    /**
     * 指定缓存的失效时间
     * @param key 缓存KEY
     * @param time 失效时间(秒)
     */
    public static void expire(String key, long time) {
        if(time > 0){
            redisTemplate.expire(key, time, TimeUnit.SECONDS);
        }
    }

    /**
     * 指定缓存的失效时间
     * @param key 缓存KEY
     * @param count 计数
     */
    public static Long increment(String key, long count) {
        Long increment = redisTemplate.opsForValue().increment(key, count);
        return increment;
    }

    /**
     * 判断是否存在key
     * @param key
     * @return
     */
    public static boolean hasKey(String key) {
        return stringRedisTemplate.hasKey(key);
    }

    /**
     * 查询过期时间
     * @param key
     * @return
     */
    public static long getExpire(String key) {
        return stringRedisTemplate.getExpire(key);
    }

    /**
     * 查询过期时间
     * @param key
     * @return
     */
    public static long getExpire(String key,TimeUnit timeUnit) {
        return redisTemplate.getExpire(key,timeUnit);
    }


    /**
     * 加入集合
     * @param key
     * @param object
     * @param time
     * @param timeUnit
     */
    public static void addSet(String key, Object object,long time ,TimeUnit timeUnit) {
        redisTemplate.opsForSet().add(key, object);
        if(time > 0){
            redisTemplate.expire(key, time, timeUnit);
        }
    }

    /**
     * 获取集合内容
     * @param key
     */
    public static Set<Object> getSet(String key) {
        return redisTemplate.opsForSet().members(key);
    }


    /**
     * 加锁并设置过期时间
     *
     * @param lockName
     * @param lockExpire 过期时间 秒
     * @return
     */
    public static boolean lock(String lockName, int lockExpire) {
        if (redisTemplate.opsForValue().setIfAbsent(lockName, lockName)) {
            redisTemplate.expire(lockName, lockExpire, TimeUnit.SECONDS);
            return true;
        }
        if (redisTemplate.getExpire(lockName) == -1) {
            //保证锁一定设置过期时间
            redisTemplate.expire(lockName, lockExpire, TimeUnit.SECONDS);
        }
        return false;
    }

    /**
     *  加锁并设置过期时间
     * @param lockName
     * @param lockExpire
     * @param timeUnit
     * @return
     */
    public static boolean lock(String lockName, int lockExpire,TimeUnit timeUnit){
        if (redisTemplate.opsForValue().setIfAbsent(lockName, lockName)) {
            redisTemplate.expire(lockName, lockExpire, timeUnit);
            return true;
        }
        if (redisTemplate.getExpire(lockName) == -1) {
            //保证锁一定设置过期时间
            redisTemplate.expire(lockName, lockExpire, timeUnit);
        }
        return false;
    }

    /**
     *  加锁并设置过期时间
     * @param lockName
     * @param lockExpire
     * @param timeUnit
     * @return
     */
    public static void lockTemplate(String lockName, int lockExpire,TimeUnit timeUnit,Runnable runnable) throws Exception{
            if(!lock(lockName,lockExpire,timeUnit)){
                throw new BizException("操作频繁，请稍后再试");
            }
        try{
            runnable.run();
        }finally {
            releaseLock(lockName);
        }
    }

    /**
     * 释放锁
     * @param lockName
     */
    public static void releaseLock(String lockName){
        redisTemplate.delete(lockName);
    }

    /**
     * 存map
     * @param key
     * @param hashKy
     * @param value
     * @param time
     * @param timeUnit
     */
    public static void hput(String key,Object hashKy, Object value, long time ,TimeUnit timeUnit){
        redisTemplate.opsForHash().put(key,hashKy,value);
        if(time > 0){
            redisTemplate.expire(key, time, timeUnit);
        }
    }

    /**
     * 取map指定key的值
     * @param key
     * @param hashKy
     */
    public static <T> T hget(String key,Object hashKy){
        return (T)  redisTemplate.opsForHash().get(key,hashKy);
    }

    /**
     * 向list尾部追加记录
     * @param key 键
     * @param value 值
     * @return list中记录总数
     */
    public static Long lpush(String key, Object value){
        return redisTemplate.opsForList().leftPush(key, value);
    }

    public static RedisTemplate<String, Object> getRedisTemplate(){
        return redisTemplate;
    }

    /**
     * 获取list的长度
     * @param key 键
     * @return 长度
     */
    public static Long lsize(String key){
        return redisTemplate.opsForList().size(key);
    }


}
